/// 本文件由reazhuang@outlook.com开发编写 *CodeMaid自动格式化*
/// 本文件主要构建成layui-form-item
/// 验证功能全部移到单独的组件中写，这里只处理验证的小红星
/// 规范：
/// 1.容器的lay-filter全部定义为formitem_{Id}
/// name都在这里给
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Extensions;

namespace ReaWTM.LayuiHelper
{
	public abstract class BaseFieldTag : BaseElementTag
	{
		protected const string REQUIRED_ATTR_NAME = "field";
		private string _clearAbleClass = null;

		#region 公共属性
		public string EmptyText { get; set; }
		/// <summary>
		/// 默认值
		/// </summary>
		public string DefaultValue { get; set; }

		/// <summary>
		/// 是否禁用
		/// </summary>
		public bool Disabled { get; set; }

		/// <summary>
		/// 绑定的字段 必填
		/// </summary>
		public ModelExpression Field { get; set; }

		/// <summary>
		/// 是否隐藏标签
		/// </summary>
		[HtmlAttributeName("is-hidelabel")]
		public bool? IsHideLabel { get; set; }

		/// <summary>
		/// 点击后自动触发searchpanel搜索
		/// </summary>
		[HtmlAttributeName("is-triggersearch")]
		public bool IsTriggerSearch { get; set; }

		/// <summary>
		/// 获取列表项的接口地址
		/// 只对combobox、tree有效
		/// </summary>
		public string ItemUrl { get; set; }

		/// <summary>
		/// 表识为内容编辑链接，内容中会出现按钮，用ff.OpenDialog打开 优先级
		/// </summary>
		public string LabelEditUrl { get; set; }

		/// <summary>
		/// 表识为内容查看链接，内容中不会出现按钮 用ff.basefield_OpenDroplist打开 优先级 低
		/// </summary>
		public string LabelText { get; set; }

		public string LabelViewUrl { get; set; }
		public int? LabelWidth { get; set; }

		/// <summary>
		/// layui的lay-verify验证
		/// </summary>
		public string LayVerify { get; set; }

		public string Name { get; set; }
		public string PaddingText { get; set; }
		public bool? Required { get; set; }

		#endregion

		#region 公共事件

		/// <summary>
		/// 表识为按钮链接，用用户自定义方法打开，优先级最高
		/// </summary>
		public string LabelClickFunc { get; set; }

		#endregion

		public void SetDefaultEmpty(string emptyText)
		{
			if (string.IsNullOrEmpty(EmptyText))
			{
				EmptyText = emptyText;
			}
		}
		private string labelLink { get; set; }

		public override void Process(TagHelperContext context, TagHelperOutput output)
		{
			UseCascadeParameter<FormTagHelper>(context, x =>
			{
				if (x.LabelWidth != null)
				{
					LabelWidth = x.LabelWidth;
				}
			});
			SetId(output);

			if (!string.IsNullOrEmpty(EmptyText))
			{
				output.Attributes.Add("placeholder", EmptyText);
			}


			output.Attributes.Add("wtm-name", GetName(context));
			SetName(context, output);

			if (this is HiddenTagHelper)
			{
				return;
			}

			if (IsTriggerSearch)
			{
				//按下回车后后自动触发SearchPanel搜索
				output.Attributes.Add("is-triggersearch", "true");
			}
			SetDisabled(output);
			SetFormItem(context, output);

			base.Process(context, output);
		}

		protected virtual string GetDefaultValue()
		{
			if (Field?.Model != null)
			{
				DefaultValue = Field.Model.ToString();
			}
			return DefaultValue;
		}

		/// <summary>
		/// 用于手动构造input时
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		protected virtual string GetName(TagHelperContext context)
		{
			//无绑定字段则不执行
			if (Field == null) return null;

			//如果在SearchPanel中，则移除"Searcher."前缀
			if (context.Items.ContainsKey(nameof(SearchPanelTagHelper)))
			{
				return string.IsNullOrEmpty(Name) ? Field.Name.Replace("Searcher.", "") : Name;
			}
			else
			{
				return string.IsNullOrEmpty(Name) ? Field.Name : Name;
			}
		}

		protected virtual void SetName(TagHelperContext context, TagHelperOutput output)
		{
			//无绑定字段则不执行
			if (Field == null) return;

			//只设定一次
			if (output.Attributes.ContainsName("name")) return;

			//如果在SearchPanel中，则移除"Searcher."前缀
			if (context.Items.ContainsKey(nameof(SearchPanelTagHelper)))
			{
				output.Attributes.SetAttribute("name", string.IsNullOrEmpty(Name) ? Field.Name.Replace("Searcher.", "") : Name);
			}
			else
			{
				output.Attributes.SetAttribute("name", string.IsNullOrEmpty(Name) ? Field.Name : Name);
			}
		}

		/// <summary>
		/// 继承类重写该方法，父类在检测需要时调用
		/// </summary>
		/// <param name="output"></param>
		protected virtual void SetRequired(TagHelperOutput output)
		{
			string layverify = "required";
			if (!string.IsNullOrEmpty(LayVerify))
			{
				layverify = $"{layverify}|{LayVerify}";
			}

			output.Attributes.SetAttribute("lay-verify", $"{layverify}");
			output.Attributes.Add("lay-reqText", $"{THProgram._localizer["Validate.{0}required", Field?.Metadata?.DisplayName ?? Field?.Metadata?.Name]}");
		}

		/// <summary>
		/// 获取必填项的小红星
		/// </summary>
		/// <returns></returns>
		private void CheckRequired(TagHelperOutput output)
		{
			var isFormItem = this is not DisplayTagHelper;
			var required = Required == true || (Field != null && Field.Metadata.IsRequired && Field.Name.Contains("[-1]") == false);
			if (isFormItem && required)
			{
				SetRequired(output);
				Required = true;
			}
			else
			{
				Required = false;
			}
		}

		private string GetClearableClass(TagHelperOutput output)
		{
			if (_clearAbleClass == null)
			{
				if (this is TextBoxTagHelper txtItem)
				{
					_clearAbleClass = txtItem.Clearable ? "layui-input-wrap-affix" : null;
					output.Attributes.Add("lay-affix", "clear");
				}
			}
			return _clearAbleClass;
		}

		private string GetLabelWidthString(TagHelperContext context)
		{
			if (LabelWidth != null)
			{
				return $"width:{LabelWidth}px;";
			}
			return "";
		}

		private void SetDisabled(TagHelperOutput output)
		{
			if (Disabled)
			{
				if (this is DateTimeTagHelper)
				{
					output.Attributes.SetAttribute("disabled", null);
				}
				else
				{
					output.Attributes.SetAttribute("readonly", null);
				}
				output.Attributes.TryGetAttribute("class", out TagHelperAttribute oldclass);
				output.Attributes.SetAttribute("class", "layui-disabled " + (oldclass?.Value ?? string.Empty));
			}
		}

		private void SetFormItem(TagHelperContext context, TagHelperOutput output)
		{
			StringBuilder preBuilder = new StringBuilder();
			StringBuilder postBuilder = new StringBuilder();

			CheckRequired(output);

			//如果用户想隐藏label
			if (IsHideLabel == true)
			{
				preBuilder.Append($@"
<div class='layui-form-item layui-form'>
	<div class='{GetClearableClass(output)} { (string.IsNullOrEmpty(PaddingText) ? "layui-input-block" : "layui-input-inline")}' style='margin-left:0px'>
");
			}
			else
			{
				//设置label的内容
				SetLabelText();

				SubProcessLabel();

				preBuilder.Append($@"
<div class='layui-form-item layui-form {base.GetFontColorClass()} {base.GetFontSizeClass()} '>
    <label for='{Id}' {labelLink} class='layui-form-label {(Required == true ? "wtm-required" : "")}' style='{GetLabelWidthString(context)}' title='{LabelText}'>{LabelText}</label>
    <div class='{GetClearableClass(output)} { (string.IsNullOrEmpty(PaddingText) ? "layui-input-block" : "layui-input-inline")}' {(LabelWidth == null || string.IsNullOrEmpty(PaddingText) == false ? null : "style='margin-left:" + (LabelWidth + 5) + "px'")}>
");
			}

			if (string.IsNullOrEmpty(PaddingText))
			{
				postBuilder.Append($@"</div></div>");
			}
			else
			{
				postBuilder.Append($@"</div><div class='layui-form-mid layui-word-aux'>{PaddingText}</div></div>");
			}

			output.PreElement.SetHtmlContent(preBuilder.ToString() + output.PreElement.GetContent());
			output.PostElement.AppendHtml(postBuilder.ToString());
		}

		private void SetId(TagHelperOutput output)
		{
			if (output.Attributes.TryGetAttribute("id", out _) == false)
			{
				output.Attributes.SetAttribute("id", Id ?? null);
			}
		}

		private void SetLabelText()
		{
			if (LabelText == null)
			{
				var pro = Field?.Metadata.ContainerType.GetSingleProperty(Field?.Metadata.PropertyName);
				if (pro != null)
				{
					LabelText = pro.GetPropertyDisplayName();
				}
				else
				{
					LabelText = Field?.Metadata.DisplayName ?? Field?.Metadata.PropertyName;
				}
				if (LabelText == null)
				{
					IsHideLabel = true;
				}
			}
		}

		private void SubProcessLabel()
		{
			if (!string.IsNullOrEmpty(LabelClickFunc))
			{
				labelLink = $"rea-label-btnlink onclick='{LabelClickFunc}(this)'"; return;
			}

			if (!string.IsNullOrEmpty(LabelEditUrl))
			{
				labelLink = $"rea-label-editlink='{LabelEditUrl}'"; return;
			}

			if (!string.IsNullOrEmpty(LabelViewUrl))
			{
				labelLink = $"rea-label-viewlink='{LabelViewUrl}'"; return;
			}
		}
	}
}